package com.dhcc.DRGsHosp.infra.filter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * @title		:BusiCacheFilter.java
 * @description	:
 * @author		:liqingyang
 * @date		:2014年8月8日
 * @version     :1.0
 * @copyright   :DHCC 2013-2014
 */
public class BusiCacheFilter implements Filter {

	public static Log logger = LogFactory.getLog(BusiCacheFilter.class);

	private FilterConfig config = null;
	private HashMap expiresMap = null;
	private String encoding = null;

	public void init(FilterConfig filterConfig) {
		this.config = filterConfig;
		this.encoding = config.getInitParameter("encoding");
		if (encoding == null || encoding.length() == 0) {
			encoding = "GBK";
		}
		expiresMap = new HashMap();
		Enumeration names = config.getInitParameterNames();
		while (names.hasMoreElements()) {
			String paramName = (String) names.nextElement();
			if (!"encoding".equals(paramName)) {
				String paramValue = config.getInitParameter(paramName);
				try {
					Integer expires = Integer.valueOf(config
							.getInitParameter(paramName));
					expiresMap.put(paramName, expires);
				} catch (Exception ex) {
					// LogUtil.logError( "Filter."+paramValue+"="+paramValue);
				}
			}
		}
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 汉字问题
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		httpRequest.setCharacterEncoding(encoding);
		// chain.doFilter(request, response);
		// 压缩传输
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		String uri = httpRequest.getRequestURI();

		String transferEncoding = getGZIPEncoding((HttpServletRequest) request);
		if (transferEncoding == null) {
			setResponseHeader(httpResponse, uri, transferEncoding);
			chain.doFilter(request, response);
		} else {
			if (uri.endsWith(".ctl") || uri.endsWith("busictrl")) // 不处理的 URL
			{
				chain.doFilter(request, response);
			} else {
				setResponseHeader(httpResponse, uri, transferEncoding);
				httpResponse.setHeader("Content-Encoding", transferEncoding);
				GZIPEncodableResponse wrappedResponse = new GZIPEncodableResponse(
						(HttpServletResponse) response);
				chain.doFilter(request, wrappedResponse);
				wrappedResponse.flush();
			}
		}
	}

	public void destroy() {
	}

	private void setResponseHeader(HttpServletResponse response, String uri,
			String transferEncoding) {
		logger.debug( uri + ".Accept-Encoding: "+ transferEncoding);
		String ext = null;
		int dot = uri.lastIndexOf(".");
		if (dot != -1) {
			ext = uri.substring(dot + 1);
		}
		if (ext != null && ext.length() > 0) {
			Integer expires = (Integer) expiresMap.get(ext);
			if (expires != null) {
				// LogUtil.logDebug( uri + ".Expires: "+ expires.intValue());
				if (expires.intValue() > 0) {
					response.setHeader("Cache-Control",
							"max-age=" + expires.intValue()); // HTTP 1.1
				} else {
					response.setHeader("Cache-Control", "no-cache");
					response.setHeader("Pragma", "no-cache"); // HTTP 1.0
					response.setDateHeader("Expires", expires.intValue());
				}
			}
		}
	}

	private static String getGZIPEncoding(HttpServletRequest request) {
		String acceptEncoding = request.getHeader("Accept-Encoding");
		if (acceptEncoding == null)
			return null;
		acceptEncoding = acceptEncoding.toLowerCase();
		if (acceptEncoding.indexOf("x-gzip") >= 0) {
			return "x-gzip";
		}
		if (acceptEncoding.indexOf("gzip") >= 0) {
			return "gzip";
		}
		return null;
	}

	private class GZIPEncodableResponse extends HttpServletResponseWrapper {
		private GZIPServletStream wrappedOut;

		public GZIPEncodableResponse(HttpServletResponse response)
				throws IOException {
			super(response);
			wrappedOut = new GZIPServletStream(response.getOutputStream());
		}

		public ServletOutputStream getOutputStream() throws IOException {
			return wrappedOut;
		}

		private PrintWriter wrappedWriter;

		public PrintWriter getWriter() throws IOException {
			if (wrappedWriter == null) {
				wrappedWriter = new PrintWriter(new OutputStreamWriter(
						getOutputStream(), getCharacterEncoding()));
			}
			return wrappedWriter;
		}

		public void flush() throws IOException {
			if (wrappedWriter != null) {
				wrappedWriter.flush();
			}
			wrappedOut.finish();
		}
	}

	private class GZIPServletStream extends ServletOutputStream {
		private GZIPOutputStream outputStream;

		public GZIPServletStream(OutputStream source) throws IOException {
			outputStream = new GZIPOutputStream(source);
		}

		public void finish() throws IOException {
			outputStream.finish();
		}

		public void write(byte[] buf) throws IOException {
			outputStream.write(buf);
		}

		public void write(byte[] buf, int off, int len) throws IOException {
			outputStream.write(buf, off, len);
		}

		public void write(int c) throws IOException {
			outputStream.write(c);
		}

		public void flush() throws IOException {
			outputStream.flush();
		}

		public void close() throws IOException {
			outputStream.close();
		}

        /**   
         * <p>Title: isReady</p>   
         * <p>Description: </p>   
         * @return   
         * @see javax.servlet.ServletOutputStream#isReady()   
         */  
        @Override
        public boolean isReady() {
            // TODO Auto-generated method stub
            return false;
        }

        /**   
         * <p>Title: setWriteListener</p>   
         * <p>Description: </p>   
         * @param arg0   
         * @see javax.servlet.ServletOutputStream#setWriteListener(javax.servlet.WriteListener)   
         */  
        @Override
        public void setWriteListener(WriteListener arg0) {
            // TODO Auto-generated method stub
            
        }
	}

}
